package com.sonic.db.dao;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Restrictions;

import com.sonic.db.utils.MQHibernateUtil;
import com.sonic.dto.db.MqtSecurityDetails;
import com.sonic.dto.db.MqtTableSecurities;
import com.sonic.dto.db.MqtTransList;
import com.sonic.dto.db.MqtTransListUnion;
import com.sonic.dto.ws.services.instrument.details.MQSecurityDetailsRequest;
import com.sonic.dto.ws.services.instrument.details.MQSecurityDetailsResponse;
import com.sonic.dto.ws.services.instrument.transactions.MQSecurityTransactionsDTO;
import com.sonic.dto.ws.services.instrument.transactions.MQSecurityTransactionsRequest;
import com.sonic.dto.ws.services.instrument.transactions.MQSecurityTransactionsResponse;
import com.sonic.log.ejb.impl.MQLogger;

public class MQSecurityDAO {
	private static MQLogger logger = new MQLogger(MQSecurityDAO.class, "MQ-SECURITY-DAO");
	private static SimpleDateFormat timeFormatter = new SimpleDateFormat("kk:mm:ss");
	private static SimpleDateFormat dateTimeFormatter = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss");
	private Session session;
	
	private Object ownership;
	
	private MqtTableSecurities getSecurity(String securityShortname) {
		Criteria criteria = session.createCriteria(MqtTableSecurities.class)
		.add(Restrictions.eq("securityShortname", securityShortname.trim()));
		MqtTableSecurities security = (MqtTableSecurities) criteria.uniqueResult();
		return security;
	}
	
	public MQSecurityDetailsResponse getSecurityDetails(MQSecurityDetailsRequest request) {
		final String methodName = "getSecurityDetails()";
		MQSecurityDetailsResponse response = new MQSecurityDetailsResponse();     
		Transaction transaction = session.beginTransaction();        
        transaction.begin();
        
		final MqtTableSecurities security = getSecurity(request.getSecurityShortName());
		if(security != null) {
			Criteria criteria = session.createCriteria(MqtSecurityDetails.class)
			.add(Restrictions.eq("mqtTableSecurities", security));
			MqtSecurityDetails securityDetails = (MqtSecurityDetails) criteria.uniqueResult();
			
			if(securityDetails != null) {
				response.setSecDetailsStatusCode(0);
				response.setSecDetailsStatusMsg(request.getSecurityShortName());
				response.setAlteration(securityDetails.getAlteration());
				if(securityDetails.getClosedValue() != null)
					response.setClosedValue(securityDetails.getClosedValue().doubleValue());
				response.setForkValue(securityDetails.getForkValue());
				response.setLop(securityDetails.getLop());
				response.setMinMax(securityDetails.getMinMax());
				response.setOpeningPrice(securityDetails.getOpeningPrice().doubleValue());
				response.setOverallDeals(securityDetails.getOverallDeals().doubleValue());
				if(securityDetails.getPayoff() != null)
					response.setPayoff(securityDetails.getPayoff());
				response.setReferencePrice(securityDetails.getReferencePrice().doubleValue());
				response.setSessionTime(timeFormatter.format(securityDetails.getSessionTime()));
				response.setSpotPrice(securityDetails.getSpotPrice().doubleValue());
				response.setTko(securityDetails.getTko());
				response.setVolume(securityDetails.getVolume());
				session.clear();
		        transaction.commit();
			} else {
				logger.debug(methodName, " --- There is no security details for security with shortName: " + request.getSecurityShortName());
				response.setSecDetailsStatusCode(-1);
				response.setSecDetailsStatusMsg("There is no security details for security with shortName: " + request.getSecurityShortName());
				transaction.rollback();
			}
		} else {
			logger.debug(methodName, " --- There is no security with shortName: " + request.getSecurityShortName());
			response.setSecDetailsStatusCode(-1);
			response.setSecDetailsStatusMsg("There is no security with shortName: " + request.getSecurityShortName());
			transaction.rollback();
		}        
		return response;
	}
	
	public MQSecurityTransactionsResponse getSecurityTransactions(MQSecurityTransactionsRequest request) {
		final String methodName = "getSecurityTransactions()";
		MQSecurityTransactionsResponse response = new MQSecurityTransactionsResponse();
		Transaction transaction = session.beginTransaction();        
        transaction.begin();
        
		final MqtTableSecurities security = getSecurity(request.getSecurityShortName());
		if(security != null) {
			
			Date dateFrom = null;
			if(request.getDateFrom() != null) {
				try {
		            dateFrom = dateTimeFormatter.parse(request.getDateFrom());
	            } catch (ParseException e) {}
			}
            
            Date dateTo = null;
            if(request.getDateTo() != null) {
				try {
		            dateTo = dateTimeFormatter.parse(request.getDateTo());
	            } catch (ParseException e) {}
            }
			
            Criteria criteria = null;
    		if(dateFrom == null && dateTo == null) {		
    			criteria = session.createCriteria(MqtTransList.class)
    			.add(Restrictions.eq("mqtTableSecurities", security));			
    		} else if(dateFrom == null) {
    			criteria = session.createCriteria(MqtTransList.class)
    			.add(Restrictions.eq("mqtTableSecurities", security))
    			.createCriteria("mqtTransListUnions", Criteria.LEFT_JOIN)			
    			.createCriteria("mqtTransListValues", Criteria.LEFT_JOIN)
    			.add(Expression.le("sessionTime", dateTo));
    		} else if(dateTo == null) {
    			criteria = session.createCriteria(MqtTransList.class)
    			.add(Restrictions.eq("mqtTableSecurities", security))
    			.createCriteria("mqtTransListUnions", Criteria.LEFT_JOIN)			
    			.createCriteria("mqtTransListValues", Criteria.LEFT_JOIN)
    			.add(Expression.ge("sessionTime", dateFrom));
    		} else {
    			criteria = session.createCriteria(MqtTransList.class)
    			.add(Restrictions.eq("mqtTableSecurities", security))
    			.createCriteria("mqtTransListUnions", Criteria.LEFT_JOIN)			
    			.createCriteria("mqtTransListValues", Criteria.LEFT_JOIN)
    			.add(Expression.between("sessionTime", dateFrom, dateTo));			
    		}
			MqtTransList securityTransactions = (MqtTransList) criteria.uniqueResult();
			
			if(securityTransactions != null) {
				response.setSecTransactionsStatusCode(0);
				response.setSecTransactionsStatusMsg(request.getSecurityShortName());
				
				List<MQSecurityTransactionsDTO> securityTransactionsWS = new ArrayList<MQSecurityTransactionsDTO>();		
				TreeSet<MqtTransListUnion> treeSet = new TreeSet<MqtTransListUnion>(new Comparator<MqtTransListUnion>() {
					public int compare(MqtTransListUnion o1, MqtTransListUnion o2) {
						return o1.getId()-o2.getId();
		            }    		
		    	});
		    	treeSet.addAll(securityTransactions.getMqtTransListUnions());
		    	Iterator<MqtTransListUnion> iter = treeSet.iterator();
		    	
				while (iter.hasNext()) {
		            MqtTransListUnion mqtTransListUnion = (MqtTransListUnion) iter.next();	  
		            securityTransactionsWS.add(new MQSecurityTransactionsDTO(
		            		timeFormatter.format(mqtTransListUnion.getMqtTransListValues().getSessionTime()),
		            		mqtTransListUnion.getMqtTransListValues().getPriceSpot().doubleValue(),
		            		mqtTransListUnion.getMqtTransListValues().getVolume()));
		        }			
				response.setSecurityTransactions(securityTransactionsWS);
		        session.clear();
		        transaction.commit();
			} else {
				logger.debug(methodName, " --- There are no security transactions for security with shortName: " + request.getSecurityShortName());
				response.setSecTransactionsStatusCode(-1);
				response.setSecTransactionsStatusMsg("There are no security transactions for security with shortName: " + request.getSecurityShortName());
				transaction.rollback();
			}
		} else {
			logger.debug(methodName, " --- There is no security with shortName: " + request.getSecurityShortName());
			response.setSecTransactionsStatusCode(-1);
			response.setSecTransactionsStatusMsg("There is no security with shortName: " + request.getSecurityShortName());
			transaction.rollback();
		}        
		return response;
	}
	
	public MQSecurityDAO() {
		try {
			ownership = MQHibernateUtil.createSession();
			session = MQHibernateUtil.getSession();
		} catch (Exception e) {
			logger.debug("MQSecurityDAO", "Could not create database session, exception: " + e.getMessage());
		}
	}
	
	public void releaseResources() {
		try {
			MQHibernateUtil.closeSession(ownership);
		} catch (Exception e) {
			logger.debug("releaseResources()", "Could not destroy database session, exception: " + e.getMessage());
		}
	}
}